// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-12-11

package filter

import (
	"context"
	"fmt"
	"gitee.com/go-libs/log"
	"strings"
)

// This component used to match in or not in operations.
type valueForIn struct {
	Err       error
	ErrExists bool
	Field     Field

	expects []string
	query   string
}

// + Implemented

func (o *valueForIn) GetError() error                       { return o.Err }
func (o *valueForIn) GetField() Field                       { return o.Field }
func (o *valueForIn) HasError() bool                        { return o.ErrExists }
func (o *valueForIn) Match(ctx context.Context, v any) bool { return o.match(ctx, v) }
func (o *valueForIn) Query() string                         { return o.query }

// + Match

func (o *valueForIn) compare(ctx context.Context, got string) (yes bool) {
	var found = false

	for _, s := range o.expects {
		if s == got {
			found = true
			break
		}
	}

	if o.Field.GetOperator().IsIn() {
		yes = found
	} else {
		yes = !found
	}

	if log.Config().DebugOn() {
		log.Debugfc(ctx, `[filter][field=%s] match result: success="%v", expression="%s %s"`, o.Field.GetKey(), yes, got, o.query)
	}
	return
}

func (o *valueForIn) match(ctx context.Context, v any) bool {
	return o.compare(ctx, fmt.Sprintf(`%v`, v))
}

// + Access

func (o *valueForIn) buildQuery() {
	o.query = fmt.Sprintf(`%s (%s)`,
		o.Field.GetOperator(),
		strings.Join(o.expects, `,`),
	)
}

func (o *valueForIn) init(str string) Value {
	o.expects = make([]string, 0)
	o.parse(str)
	o.buildQuery()
	return o
}

func (o *valueForIn) parse(str string) {
	// Skip empty string.
	if str = strings.TrimSpace(str); str == "" {
		return
	}

	// Remove brackets.
	if regexMatchBracket.MatchString(str) {
		str = regexMatchBracket.ReplaceAllString(str, "$1")
		o.parse(str)
		return
	}

	// History sets.
	set := make(map[string]bool)

	// Range list of values.
	for _, str = range strings.Split(str, ",") {
		// Collect item.
		if str = strings.TrimSpace(str); str != "" {
			for _, s := range []string{`'`, `"`} {
				str = strings.TrimSpace(
					strings.TrimPrefix(strings.TrimSuffix(str, s),
						s,
					),
				)
			}
		}

		// Repeat value.
		if _, ok := set[str]; ok {
			continue
		}

		// Append.
		set[str] = true
		o.expects = append(o.expects, str)
	}
}
